home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Programming / ace_gpl_release / src / ace / c / opt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-04  |  7.0 KB  |  333 lines

  1. /* << ACE >>
  2.  
  3.    -- Amiga BASIC Compiler --
  4.  
  5.    ** Optimiser **
  6.    ** Copyright (C) 1998 David Benn
  7.    ** 
  8.    ** This program is free software; you can redistribute it and/or
  9.    ** modify it under the terms of the GNU General Public License
  10.    ** as published by the Free Software Foundation; either version 2
  11.    ** of the License, or (at your option) any later version.
  12.    **
  13.    ** This program is distributed in the hope that it will be useful,
  14.    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    ** GNU General Public License for more details.
  17.    **
  18.    ** You should have received a copy of the GNU General Public License
  19.    ** along with this program; if not, write to the Free Software
  20.    ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21.  
  22.    Author: David J Benn
  23.      Date: 8th,9th,11th,14th June 1992,
  24.        2nd,5th July 1992,
  25.        6th December 1992,
  26.        25th December 1993,
  27.        5th,9th-11th April 1994,
  28.        24th July 1994,
  29.        11th September 1994,
  30.        11th March 1995
  31. */
  32.  
  33. #include "acedef.h"
  34.  
  35. /* globals */
  36. CODE  *curr, *first, *second;
  37. char  opcode[40],srcopr[40],destopr[40];
  38. SHORT peep=0;
  39.  
  40. /* externals */
  41. extern    CODE    *code;
  42.  
  43. /* functions */
  44. BOOL is_a_move(opcode)
  45. char *opcode;
  46. {
  47.  if (opcode[0] == 'm')
  48.  {
  49.    if (strcmp(opcode,"move.b") == 0) return(TRUE);
  50.    else
  51.    if (strcmp(opcode,"move.w") == 0) return(TRUE);
  52.    else
  53.    if (strcmp(opcode,"move.l") == 0) return(TRUE);
  54.    else
  55.        return(FALSE);
  56.  }
  57.  else
  58.      return(FALSE);
  59. }
  60.  
  61. BOOL push_pop_pair()
  62. {
  63. /* 
  64. ** Eliminate:     stack push/pop pair
  65. **           eg: move.l d0,-(sp)
  66. **                    move.l (sp)+,d1       ->       move.l d0,d1         [A]
  67. **
  68. **      OR
  69. ** 
  70. **        redundant dest/src register pair (from other optimisations) 
  71. **        eg: move.l #3,d0
  72. **            move.l d0,-4(a4)    ->    move.l #3,-4(a4)    [B]
  73. **
  74. **        Don't apply this transformation to instructions which
  75. **        use labelled (BSS/DATA) items since ACE (esp. in gfx.c)
  76. **        does things with such items which if optimised can lead
  77. **        to a loss of valid code (eg. a d0 move may be eliminated
  78. **        when it is required for a shared library function call;
  79. **        see the code for COLOR as an example). This should only
  80. **        be a problem for case [B] above, not case [A] since no
  81. **        registers are removed in [A].
  82. */
  83.  
  84.    if (strcmp(first->opcode,second->opcode)==0 && 
  85.        is_a_move(first->opcode)
  86.  
  87.      &&
  88.  
  89.        ((strcmp(first->destopr,"-(sp)")==0 && 
  90.         strcmp(second->srcopr,"(sp)+")==0)        /* [A] */
  91.  
  92.      ||     
  93.      
  94.        (strcmp(first->destopr,"d0")==0 && 
  95.         strcmp(second->srcopr,"d0")==0 &&
  96.     first->srcopr[0] != '_' && 
  97.     second->destopr[0] != '_')))            /* [B] */
  98.    {
  99.     /* copy required code */
  100.     strcpy(opcode,first->opcode);
  101.     strcpy(srcopr,first->srcopr);
  102.     strcpy(destopr,second->destopr);
  103.  
  104.     /* modify first line */
  105.     if (strcmp(srcopr,destopr) != 0)
  106.        change(first,opcode,srcopr,destopr);  /* src operand != dest operand */ 
  107.     else 
  108.     {
  109.     /* 
  110.      ** src operand == dest operand 
  111.     **
  112.     ** eg.       move.l d0,-(sp)
  113.     **      move.l (sp)+,d0
  114.     **
  115.     **     =  move.l d0,d0    [elimimate this!]
  116.     */
  117.     change(first,"nop","  ","  ");                          
  118.     peep++;
  119.     }
  120.  
  121.     /* eliminate second line */
  122.     change(second,"nop","  ","  ");
  123.  
  124.     /* skip second line */
  125.     curr = second->next;
  126.  
  127.     peep++;
  128.  
  129.     return(TRUE);
  130.    }
  131.    else
  132.        return(FALSE);
  133. }
  134.  
  135. BOOL sign_bit_extension()
  136. {
  137. /*
  138. ** Combine:    move.b #n,dm
  139. **        ext.w  dm
  140. **
  141. **       ->    move.w #n,dm
  142. **
  143. **       OR
  144. **        move.w #n,dm
  145. **        ext.l  dm
  146. **
  147. **       ->    move.l #n,dm
  148. **
  149. **
  150. **      NOT    move.w (sp)+,dm
  151. **        ext.l  dm
  152. **
  153. **        since this would change a short pop into a long pop!
  154. **
  155. **      NOR    move.w _mylabel,dm
  156. **        ext.l  dm
  157. **
  158. **        since this would try to move data beyond the confines
  159. **        of the BSS/DATA block starting from _mylabel. 
  160. **
  161. **     In short, this technique is only useful for immediate mode 
  162. **     addressed operands.
  163. **
  164. **     Note that this kind of optimisation may lead to redundant register 
  165. **     moves (eg. compile the 2 line program: 'DEFLNG a-z / X = 1' and
  166. **     work through the transformations), so push_pop_pair() should be
  167. **     called after this function.
  168. */    
  169.  
  170.         if (strcmp(second->opcode,"ext.l") == 0 &&
  171.         strcmp(first->opcode,"move.w") == 0 &&
  172.         first->srcopr[0] == '#') 
  173.     {        
  174.         strcpy(opcode,"move.l");
  175.         strcpy(srcopr,first->srcopr);
  176.         strcpy(destopr,first->destopr);
  177.         change(first,opcode,srcopr,destopr);
  178.         change(second,"nop","  ","  ");
  179.             curr = second->next;
  180.         peep++;
  181.         return(TRUE);
  182.     }
  183.     else
  184.         if (strcmp(second->opcode,"ext.w") == 0 &&
  185.         strcmp(first->opcode,"move.b") == 0 &&        
  186.         first->srcopr[0] == '#') 
  187.     {        
  188.         strcpy(opcode,"move.w");
  189.         strcpy(srcopr,first->srcopr);
  190.         strcpy(destopr,first->destopr);
  191.         change(first,opcode,srcopr,destopr);
  192.         change(second,"nop","  ","  ");
  193.             curr = second->next;
  194.         peep++;
  195.         return(TRUE);
  196.     }
  197.     else
  198.         return(FALSE);
  199. }
  200.  
  201. BOOL negate_constant()
  202. {
  203. /*
  204. ** Constant Negation:    move.w #n,-(sp)
  205. **            neg.w  (sp)
  206. **            move.w (sp)+,d0        
  207. **    becomes:    
  208. **            move.w #-n,-(sp)
  209. **            move.w(sp)+,d0
  210. **
  211. **    The latter is then a candidate for removal by push_pop_pair().    
  212. */
  213.  
  214.     if (((strcmp(second->opcode,"neg.w") == 0 &&
  215.          strcmp(first->opcode, "move.w") == 0) ||
  216.  
  217.         (strcmp(second->opcode,"neg.l") == 0 &&
  218.          strcmp(first->opcode,"move.l") == 0)) &&
  219.  
  220.             first->srcopr[0] == '#')
  221.     {
  222.         strcpy(opcode,first->opcode);
  223.         srcopr[0] = '#'; 
  224.  
  225.         if (first->srcopr[1] != '-')
  226.         {
  227.             /*
  228.             ** Constant is not negative so negate it.
  229.             */
  230.             srcopr[1] = '-'; srcopr[2] = '\0';
  231.             strcat(srcopr,&first->srcopr[1]);
  232.         }
  233.         else
  234.         {
  235.             /*
  236.             ** Constant is negative so skip '-'.
  237.             */
  238.             srcopr[1] = '\0';
  239.             strcat(srcopr,&first->srcopr[2]);
  240.         }
  241.  
  242.         strcpy(destopr,first->destopr);
  243.         change(first,opcode,srcopr,destopr);
  244.         change(second,"nop","  ","  ");
  245.         curr = second->next;
  246.         peep++;        
  247.         return(TRUE);        
  248.     }
  249.     else
  250.         return(FALSE);            
  251. }
  252.  
  253. SHORT peephole()
  254. {
  255. /* 
  256. ** Perform a series of peephole 
  257. ** optimisations on the code list.
  258. */
  259. BOOL past_head;
  260. int  opt_type;
  261.  
  262.   if (code == NULL) return;
  263.  
  264.     for (opt_type=1;opt_type<=4;opt_type++)
  265.     {
  266.     /* Start of code list */
  267.     curr = code;
  268.  
  269.     past_head = FALSE;
  270.  
  271.     do
  272.      {
  273.         /* get next two lines of code (skipping nops) */
  274.         first = curr;
  275.         if (first != NULL) 
  276.         {
  277.             second = first->next;
  278.  
  279.             while (second && strcmp(second->opcode,"nop") == 0)
  280.                   second = second->next; 
  281.  
  282.             curr = second;
  283.         }
  284.         else
  285.         {
  286.             curr = second = NULL;
  287.         }
  288.  
  289.         /* 
  290.         ** Remove redundant code in current peephole.
  291.         **
  292.         ** Only do this if we're past the head of the
  293.          ** code list but haven't yet reached the end of 
  294.         ** this list.
  295.         */
  296.           if (past_head && second != NULL)
  297.         switch(opt_type)
  298.         {
  299.             case 1 : negate_constant();
  300.                  break;
  301.  
  302.              case 2 : push_pop_pair();
  303.                  break;
  304.  
  305.             case 3 : sign_bit_extension();
  306.                  break;
  307.  
  308.             case 4 : push_pop_pair();
  309.                  break;
  310.         }
  311.  
  312.         if (!past_head) past_head = TRUE;
  313.      }
  314.      while (curr != NULL);
  315.     }
  316.  
  317.   /* total # of removals */
  318.   return(peep);
  319. }
  320.  
  321. void optimise()
  322. {
  323. SHORT peep;
  324.  
  325.  printf("\noptimising...\n");
  326.  peep = peephole();
  327.  printf("%d peephole ",peep);
  328.  if (peep == 1) 
  329.     printf("removal.");  
  330.  else
  331.     printf("removals."); /* peep==0 or peep>1 */
  332. }
  333.